package org.lim.lcpicturebackend.manager.websocket;

import groovyjarjarantlr4.v4.runtime.misc.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.lim.lcpicturebackend.manager.websocket.disruptor.PictureEditEventProducer;
import org.lim.lcpicturebackend.manager.websocket.model.PictureEditRequestMessage;
import org.lim.lcpicturebackend.manager.websocket.model.PictureEditResponseMessage;
import org.lim.lcpicturebackend.manager.websocket.model.enums.PictureEditMessageTypeEnum;
import org.lim.lcpicturebackend.manager.websocket.service.PictureEditBroadcastService;
import org.lim.lcpicturebackend.manager.websocket.service.strategy.PictureEditMessageStrategy;
import org.lim.lcpicturebackend.manager.websocket.service.strategy.PictureEditMessageStrategyFactory;
import org.lim.lcpicturebackend.model.entity.User;
import org.lim.lcpicturebackend.service.UserService;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import cn.hutool.json.JSONUtil;

import javax.annotation.Resource;
import java.util.Map;

@Component
@Slf4j
public class PictureEditHandler extends TextWebSocketHandler {

    @Resource
    private UserService userService;
    
    @Resource
    private PictureEditMessageStrategyFactory strategyFactory;
    
    @Resource
    private PictureEditBroadcastService broadcastService;

    @Resource
    private PictureEditEventProducer pictureEditEventProducer;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 保存会话到集合
        User user = (User) session.getAttributes().get("user");
        Long pictureId = (Long) session.getAttributes().get("pictureId");
        broadcastService.addSession(pictureId, session);

        // 构造响应
        PictureEditResponseMessage responseMessage = new PictureEditResponseMessage();
        responseMessage.setType(PictureEditMessageTypeEnum.INFO.getValue());
        String message = String.format("用户%s加入编辑", user.getUserName());
        responseMessage.setMessage(message);
        responseMessage.setUser(userService.getUserVO(user));
        
        // 广播给同一张图片的用户
        broadcastService.broadcastToPicture(pictureId, responseMessage);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 将消息解析为 PictureEditMessage
        PictureEditRequestMessage requestMessage = JSONUtil.toBean(message.getPayload(), PictureEditRequestMessage.class);
        
        // 从 Session 属性中获取公共参数
        Map<String, Object> attributes = session.getAttributes();
        User user = (User) attributes.get("user");
        Long pictureId = (Long) attributes.get("pictureId");

        //根据消息类型处理消息（生成消息到disruptor队列）
        pictureEditEventProducer.publishEvent(requestMessage, session, user, pictureId);

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, @NotNull CloseStatus status) throws Exception {
        Map<String, Object> attributes = session.getAttributes();
        Long pictureId = (Long) attributes.get("pictureId");
        User user = (User) attributes.get("user");
        
        // 使用退出编辑策略处理连接关闭
        PictureEditMessageStrategy exitStrategy = strategyFactory.getStrategy(PictureEditMessageTypeEnum.EXIT_EDIT);
        if (exitStrategy != null) {
            exitStrategy.handleMessage(null, session, user, pictureId);
        }

        // 删除会话
        broadcastService.removeSession(pictureId, session);

        // 响应
        PictureEditResponseMessage responseMessage = new PictureEditResponseMessage();
        responseMessage.setType(PictureEditMessageTypeEnum.INFO.getValue());
        String message = String.format("%s离开编辑", user.getUserName());
        responseMessage.setMessage(message);
        responseMessage.setUser(userService.getUserVO(user));
        broadcastService.broadcastToPicture(pictureId, responseMessage);
    }
}